-module(push_worker_pool).
-behaviour(gen_server).
-export([start_link/1, stop/0, push_notice/4]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
	     code_change/3]).

-define(TIMEOUT, 3000).
-record(state, {pid}).
-define(EPOCH, 62167219200).
-define(APNS_MSG_TIMEOUT, 3600 * 24).
-define(VOIP_MSG_TIMEOUT, 60).
-define(GC_APNS,600000). % 10分钟后关闭apns,并使用新的apns


push_notice(UId, Token, Content, Count) ->
	wpool:cast(apns_pool, {push_notice, UId ,Token, Content, Count}, next_worker).

start_link(Arg) ->
	gen_server:start_link(?MODULE, [Arg], []).

stop() ->
	gen_server:call(?MODULE, stop, ?TIMEOUT).


init(_Arg) ->
	process_flag(trap_exit, true),
	case apns:connect(cert, undefined) of
		{ok, PId} ->
			error_logger:info_msg("Apns connect:~p~n", [PId]),
			erlang:send_after(?GC_APNS,self(),{gc_apsn}),
			{ok, #state{pid = PId}};
		Other ->
			Other
	end.

handle_call(stop, _From, State) ->
	{stop, normal, State};

handle_call(Request, _From, State) ->
	{stop, {unknown_call, Request}, State}.


handle_cast({push_notice, UId, DeviceId, Content, Count}, #state{pid=PId} = State) ->
	Expiry = calendar:datetime_to_gregorian_seconds(calendar:universal_time()) - ?EPOCH + ?APNS_MSG_TIMEOUT,
	Notification = case Content of
						<<>> ->  %静音
							#{aps => #{
											badge => Count
									   }
							};
					    _ ->
							#{aps => #{
										alert => Content,
										badge => Count,
										sound => <<"notification.caf">>
									 }
							}
					end,
	NewHeader = #{
						   apns_topic => <<"bobo.sijiao">>,
						apns_priority => <<"10">>,
		    		  apns_expiration => integer_to_binary(Expiry)
				},

	T1 = os:system_time(microsecond),
	Res = apns:push_notification(PId, DeviceId, Notification ,NewHeader),
	T2 = os:system_time(microsecond),
	CastTime = (T2-T1)/1000000,
	case Res of
		{200, _, no_body} ->
			error_logger:info_msg("[~p]Push msg to apns! cast [~p] sec ",[UId,CastTime]);
		{Code, _, Reason} when Code == 400; Code == 410 ->
			ReasonContent = proplists:get_value(<<"reason">>,Reason),
			error_logger:info_msg("[UId:~p] ~p", [UId, ReasonContent]);
		Error ->
			error_logger:info_msg("[UId:~p] ~p", [UId, Error])
	end,
	{noreply, State};

handle_cast(_Msg, State) ->
	{noreply, State}.

handle_info({gc_apsn},#state{pid = OldPId } = State) ->
	error_logger:info_msg("gc apns connect."),
	case apns:connect(cert, undefined) of
		{ok, PId} ->
			error_logger:info_msg("New Apns connect:~p", [PId]),
			erlang:send_after(?GC_APNS,self(),{gc_apsn}),
			apns:close_connection(OldPId),
			{noreply, State#state{pid=PId}};
		Error ->
			error_logger:info_msg("New Apns connect fail:~p,2 sec try agagin", [Error]),
			erlang:send_after(2000,self(),{gc_apsn}),
			{noreply,State}
	end;

handle_info({apns_response, _Server, _StreamID, _Response} = _Info, State) ->
	{noreply, State};

handle_info(_Info, State) ->
	{noreply, State}.

terminate(Reason,  #state{pid=PId} = _State) ->
	error_logger:info_msg("work_pool:~p, is terminate the reason :~p~n",  [PId, Reason]),
	ok.

code_change(_, State, _Extra) ->
	{ok, State}.
